﻿using ActiproSoftware.Windows.Shapes;
using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Data.DDL;
using ArcGIS.Core.Geometry;
using ArcGIS.Core.Internal.CIM;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Core.Geoprocessing;
using ArcGIS.Desktop.Editing;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using Aspose.Cells;
using Aspose.Cells.Drawing;
using CCTool.Scripts.Manager;
using CCTool.Scripts.ToolManagers;
using CCTool.Scripts.ToolManagers.Extensions;
using CCTool.Scripts.ToolManagers.Managers;
using MathNet.Numerics.LinearAlgebra.Factorization;
using Microsoft.Office.Core;
using NPOI.OpenXmlFormats.Dml.Diagram;
using NPOI.OpenXmlFormats.Vml;
using NPOI.SS.Formula.PTG;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Geometry = ArcGIS.Core.Geometry.Geometry;
using Polygon = ArcGIS.Core.Geometry.Polygon;
using Polyline = ArcGIS.Core.Geometry.Polyline;
using SpatialReference = ArcGIS.Core.Geometry.SpatialReference;

namespace CCTool.Scripts.CusTool4
{
    /// <summary>
    /// Interaction logic for ExportPointAndPolyline2.xaml
    /// </summary>
    public partial class ExportPointAndPolyline2 : ArcGIS.Desktop.Framework.Controls.ProWindow
    {
        // 工具设置标签
        readonly string toolSet = "ExportPointAndPolyline2";
        public ExportPointAndPolyline2()
        {
            InitializeComponent();

            textGDBPath.Text = BaseTool.ReadValueFromReg(toolSet, "outputFolder");

        }

        // 定义一个进度框
        private ProcessWindow processwindow = null;
        string tool_name = "生成界址点、界址线(辣椒)";

        private void combox_fc_DropDown(object sender, EventArgs e)
        {
            UITool.AddFeatureLayersToComboxPlus(combox_fc);
        }

        private async void btn_go_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // 获取参数
                string fc = combox_fc.ComboxText();
                string nameField = combox_field.ComboxText();
                string qlrField = combox_qlrField.ComboxText();
                string outputFolder = textGDBPath.Text;

                string defGDB = Project.Current.DefaultGeodatabasePath;
                string outPoint = @$"{defGDB}\outPoint";
                string outPolyline = @$"{defGDB}\outPolyline";


                // 判断参数是否选择完全
                if (fc == "" || nameField == "" || qlrField == "" || outputFolder == "")
                {
                    MessageBox.Show("有必选参数为空！！！");
                    return;
                }

                BaseTool.WriteValueToReg(toolSet, "outputFolder", outputFolder);

                // 打开进度框
                ProcessWindow pw = UITool.OpenProcessWindow(processwindow, tool_name);
                pw.AddMessageTitle(tool_name);

                Close();
                await QueuedTask.Run(() =>
                {
                    pw.AddMessageStart("检查数据");
                    // 检查数据
                    List<string> errs = CheckData(fc, nameField, qlrField);
                    // 打印错误
                    if (errs.Count > 0)
                    {
                        foreach (var err in errs)
                        {
                            pw.AddMessageMiddle(10, err, Brushes.Red);
                        }
                        return;
                    }

                    // 判断一下是否存在目标GDB，如果有的话，就删掉重建
                    string pointGDB = $@"{outputFolder}\导出界址点.gdb";
                    string polylingGDB = $@"{outputFolder}\导出界址线.gdb";
                    if (Directory.Exists(pointGDB))
                    {
                        Arcpy.Delect(pointGDB);
                    }
                    if (Directory.Exists(polylingGDB))
                    {
                        Arcpy.Delect(polylingGDB);
                    }
                    Arcpy.CreateFileGDB(outputFolder, "导出界址点");
                    Arcpy.CreateFileGDB(outputFolder, "导出界址线");

                    // 如果存在临时要素，也删掉
                    if (defGDB.IsHaveFeaturClass("outPoint"))
                    {
                        Arcpy.Delect(outPoint);
                    }
                    if (defGDB.IsHaveFeaturClass("outPolyline"))
                    {
                        Arcpy.Delect(outPolyline);
                    }

                    // 获取目标FeatureLayer
                    FeatureLayer featurelayer = fc.TargetFeatureLayer();
                    // 获取坐标系
                    SpatialReference sr = featurelayer.GetSpatialReference();
                    // 确保要素类的几何类型是多边形
                    if (featurelayer.ShapeType != esriGeometryType.esriGeometryPolygon)
                    {
                        // 如果不是多边形类型，则输出错误信息并退出函数
                        MessageBox.Show("该要素类不是多边形类型。");
                        return;
                    }

                    pw.AddMessageMiddle(10, $"处理面要素，按西北角起始，顺时针重排");

                    Dictionary<List<List<MapPoint>>, string> mapPoints = new Dictionary<List<List<MapPoint>>, string>();
                    // 遍历面要素类中的所有要素
                    RowCursor cursor = featurelayer.TargetSelectCursor();
                    while (cursor.MoveNext())
                    {
                        using var feature = cursor.Current as Feature;
                        string name = feature[nameField]?.ToString();

                        // 获取要素的几何
                        Polygon geometry = feature.GetShape() as Polygon;

                        if (geometry != null)
                        {
                            // 获取面要素的所有折点【按西北角起始，顺时针重排】
                            mapPoints.Add(geometry.ReshotMapPoint(), name);
                        }

                    }

                    pw.AddMessageMiddle(10, "创建界址点");
                    // 创建点要素
                    CreatePoint(outPoint, sr, mapPoints);

                    pw.AddMessageMiddle(10, "创建界址线");
                    // 创建线要素
                    CreatePolyline(outPolyline, sr, mapPoints);

                    pw.AddMessageMiddle(20, "拆分存入GDB");
                    // 分割
                    Arcpy.SplitByAttributes(outPoint, pointGDB, "BJ");
                    Arcpy.SplitByAttributes(outPolyline, polylingGDB, "BJ");

                    pw.AddMessageMiddle(20, "输出界址点表");
                    CreateExcel(fc, nameField, qlrField, outputFolder);


                    // 删除中间数据
                    Arcpy.Delect(outPoint);
                    Arcpy.Delect(outPolyline);

                });

                pw.AddMessageEnd();
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message + ee.StackTrace);
                return;
            }
        }

        private void CreateExcel(string fc, string nameField, string qlrField,  string outputFolder)
        {
            
            string excelFolder = $@"{outputFolder}\界址点表";
            // 创建文件夹
            DirTool.CreateFolder(excelFolder);

            // 获取目标FeatureLayer
            FeatureLayer featurelayer = fc.TargetFeatureLayer();

            // 遍历面要素类中的所有要素
            RowCursor cursor = featurelayer.TargetSelectCursor();
            while (cursor.MoveNext())
            {
                using var feature = cursor.Current as Feature;
                // 获取要素的几何
                ArcGIS.Core.Geometry.Polygon geometry = feature.GetShape() as ArcGIS.Core.Geometry.Polygon;
                // 获取ID\名称\权利人
                string oid = feature.GetObjectID().ToString();
                string feature_name = feature[nameField]?.ToString();   // 宗地号

                string QLR = feature[qlrField]?.ToString(); ;                    // 权利人
                string JZMJ = "";                  // 建筑面积

                // 计算多边形的面积
                double xs = "亩" switch    // 单位换算
                {
                    "平方米" => 1,
                    "公顷" => 10000,
                    "平方公里" => 1000000,
                    "亩" => 666.6667,
                    _ => 0,
                };
                double polygonArea = Math.Round(geometry.Area / xs, 2);


                // 复制界址点Excel表
                string excelPath = excelFolder + @$"\{oid} - {feature_name}界址点表.xlsx";
                DirTool.CopyResourceFile(@"CCTool.Data.Excel.【模板】界址点表_多页.xlsx", excelPath);
                // 获取工作薄、工作表
                string excelFile = ExcelTool.GetPath(excelPath);
                int sheetIndex = ExcelTool.GetSheetIndex(excelPath);
                // 打开工作薄
                Workbook wb = ExcelTool.OpenWorkbook(excelFile);
                // 打开工作表
                Worksheet worksheet = wb.Worksheets[sheetIndex];
                // 获取Cells
                Cells cells = worksheet.Cells;


                // 设置分页信息
                SetPage(geometry, cells, feature_name, QLR, polygonArea, JZMJ, "亩", "", "", "");

                if (geometry != null)
                {
                    // 获取面要素的所有折点【按西北角起始，顺时针重排】
                    List<List<MapPoint>> mapPoints = geometry.ReshotMapPoint();

                    int rowIndex = 9;   // 起始行
                    int pointIndex = 1;  // 起始点序号
                    int lastRowCount = 0;  // 上一轮的行数

                    for (int i = 0; i < mapPoints.Count; i++)
                    {
                        // 输出折点的XY值和距离到Excel表
                        double prevX = double.NaN;
                        double prevY = double.NaN;

                        for (int j = 0; j < mapPoints[i].Count; j++)
                        {
                            // 写入点号
                            // J前缀
                            string jFront = "J";
                            if (pointIndex - lastRowCount == mapPoints[i].Count)    // 找到当前环的最后一点
                            {
                                worksheet.Cells[rowIndex, 1].Value = $"{jFront}{lastRowCount + 1 - i}";
                            }
                            else
                            {
                                worksheet.Cells[rowIndex, 1].Value = $"{jFront}{pointIndex - i}";
                            }

                            // 写入序号
                            worksheet.Cells[rowIndex, 0].Value = $"{pointIndex}";

                            double x = Math.Round(mapPoints[i][j].X, 3);
                            double y = Math.Round(mapPoints[i][j].Y, 3);
                            // 写入折点的XY值
                            worksheet.Cells[rowIndex, 2].Value = y;
                            worksheet.Cells[rowIndex, 3].Value = x;
                            // 设置单元格为数字型，小数位数
                            Aspose.Cells.Style style = worksheet.Cells[rowIndex, 2].GetStyle();
                            style.Number = 4;   // 数字型
                                                // 小数位数
                            style.Custom = 3 switch
                            {
                                1 => "0.0",
                                2 => "0.00",
                                3 => "0.000",
                                4 => "0.0000",
                                _ => null,
                            };
                            // 设置
                            worksheet.Cells[rowIndex, 2].SetStyle(style);
                            worksheet.Cells[rowIndex, 3].SetStyle(style);

                            // 计算当前点与上一个点的距离
                            if (!double.IsNaN(prevX) && !double.IsNaN(prevY) && rowIndex > 8)
                            {
                                string distance = Math.Sqrt(Math.Pow(x - prevX, 2) + Math.Pow(y - prevY, 2)).RoundWithFill(2);
                                // 写入距离【第一行不写入】
                                worksheet.Cells[rowIndex - 1, 4].Value = distance;
                                if (j == mapPoints[i].Count - 1)
                                {
                                    worksheet.Cells[rowIndex + 1, 4].Value = "";
                                }
                            }
                            prevX = x;
                            prevY = y;
                            // 是否跨页
                            if (rowIndex == 79 || (rowIndex - 79) % 85 == 0)
                            {
                                // 但是如果不是最后一个点，就回退
                                if (pointIndex - lastRowCount != mapPoints[i].Count)
                                {
                                    rowIndex += 11;
                                    // 点号回退1
                                    j--;
                                    pointIndex--;
                                }
                                else
                                {
                                    rowIndex += 11;
                                }
                            }
                            else
                            {
                                rowIndex += 2;
                            }
                            pointIndex++;
                        }
                        lastRowCount += mapPoints[i].Count;
                    }
                }
                // 保存
                wb.Save(excelPath);
                wb.Dispose();
            }
        }

        // 生成分页，并设置分页信息
        public static void SetPage(Polygon geometry, Cells cells, string ZDH, string QLR, double ZDMJ, string JZMJ, string zd_unit, string zbr, string js, string zbrq)
        {
            // 获取要素的界址点总数
            var pointsCount = geometry.Points.Count;
            // 计算要生成的页数
            long pageCount = (int)Math.Ceiling((double)(pointsCount - 36) / 37) + 1;

            if (pageCount == 1)   // 只有一页，就删第二页
            {
                cells.DeleteRows(83, 85);
            }
            else if (pageCount > 2)  // 多于2页
            {
                // 复制分页，前两页已有不用复制
                for (int i = 0; i < pageCount - 2; i++)
                {
                    cells.CopyRows(cells, 83, 168 + i * 85, 85);
                }
            }
            // 设置单元格
            for (int i = 0; i < pageCount; i++)
            {
                if (i == 0) // 第一页
                {
                    // 填写页码
                    cells[0, 4].Value = "第 1 页";
                    cells[1, 4].Value = $"共 {pageCount} 页";
                    // 宗地号
                    string zdhStr = cells[2, 0].StringValue;
                    cells[2, 0].Value = zdhStr.Replace("ZDH", ZDH);
                    // 权利人
                    string qlrStr = cells[3, 0].StringValue;
                    cells[3, 0].Value = qlrStr.Replace("QLR", QLR);
                    // 宗地面积
                    string zdmjStr = cells[4, 0].StringValue;
                    cells[4, 0].Value = zdmjStr.Replace("ZDMJ", ZDMJ.ToString()).Replace("平方米", zd_unit);
                    // 建筑面积
                    string jzmjStr = cells[5, 0].StringValue;
                    cells[5, 0].Value = jzmjStr.Replace("JZMJ", JZMJ);
                    // 制表人
                    cells[81, 0].Value = $"制表：{zbr}";
                    // 校审
                    cells[81, 2].Value = $"校审：{js}";
                    // 制表日期
                    cells[81, 4].Value = $"{zbrq}";

                }
                else  // 其它页
                {
                    // 填写页码
                    cells[83 + (i - 1) * 85, 4].Value = $"第 {i + 1} 页";
                    cells[84 + (i - 1) * 85, 4].Value = $"共 {pageCount} 页";
                    // 宗地号
                    string zdhStr = cells[85 + (i - 1) * 85, 0].StringValue;
                    cells[85 + (i - 1) * 85, 0].Value = zdhStr.Replace("ZDH", ZDH);
                    // 权利人
                    string qlrStr = cells[86 + (i - 1) * 85, 0].StringValue;
                    cells[86 + (i - 1) * 85, 0].Value = qlrStr.Replace("QLR", QLR);
                    // 制表人
                    cells[166 + (i - 1) * 85, 0].Value = $"制表：{zbr}";
                    // 校审
                    cells[166 + (i - 1) * 85, 2].Value = $"校审：{js}";
                    // 制表日期
                    cells[166 + (i - 1) * 85, 4].Value = $"{zbrq}";
                }

            }
        }


        // 创建点要素
        private void CreatePoint(string fcPath, SpatialReference sr, Dictionary<List<List<MapPoint>>, string> mapPoints)
        {
            string gdbPath = fcPath.TargetWorkSpace();
            string fcName = fcPath.TargetFcName();

            /// 创建点要素
            // 创建一个ShapeDescription
            var shapeDescription = new ShapeDescription(GeometryType.Point, sr)
            {
                HasM = false,
                HasZ = false
            };
            // 定义字段
            #region

            var bj = new ArcGIS.Core.Data.DDL.FieldDescription("BJ", FieldType.String);
            bj.AliasName = "宗地号";
            bj.Length = 254;

            var jzdh = new ArcGIS.Core.Data.DDL.FieldDescription("JZDH", FieldType.String);
            jzdh.AliasName = "界址点号";
            jzdh.Length = 10;

            var xzbz = new ArcGIS.Core.Data.DDL.FieldDescription("XZBZ", FieldType.Double);
            xzbz.AliasName = "X坐标值";
            xzbz.Length = 10;

            var yzbz = new ArcGIS.Core.Data.DDL.FieldDescription("YZBZ", FieldType.Double);
            yzbz.AliasName = "Y坐标值";
            yzbz.Length = 10;
            #endregion

            // 打开数据库gdb
            using Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(gdbPath)));
            // 收集字段列表
            var fieldDescriptions = new List<ArcGIS.Core.Data.DDL.FieldDescription>()
            {
                  bj, jzdh, xzbz, yzbz,
            };

            // 创建FeatureClassDescription
            var fcDescription = new FeatureClassDescription(fcName, fieldDescriptions, shapeDescription);
            // 创建SchemaBuilder
            SchemaBuilder schemaBuilder = new SchemaBuilder(gdb);
            // 将创建任务添加到DDL任务列表中
            schemaBuilder.Create(fcDescription);
            // 执行DDL
            bool success = schemaBuilder.Build();

            // 创建要素并添加到要素类中
            using FeatureClass featureClass = gdb.OpenDataset<FeatureClass>(fcName);
            /// 构建点要素
            // 创建编辑操作对象
            EditOperation editOperation = new EditOperation();
            editOperation.Callback(context =>
            {
                // 获取要素定义
                FeatureClassDefinition featureClassDefinition = featureClass.GetDefinition();
                // 循环创建点
                foreach (var mp in mapPoints)
                {
                    var mpList = mp.Key;
                    for (int j = 0; j < mpList.Count; j++)
                    {
                        for (int k = 0; k < mpList[j].Count; k++)
                        {
                            // 创建RowBuffer
                            using RowBuffer rowBuffer = featureClass.CreateRowBuffer();
                            MapPoint pt = mpList[j][k];
                            // 写入字段值和标记代码
                            int dh = k == mpList[j].Count - 1 ? 1 : k + 1;
                            rowBuffer["JZDH"] = $"J{dh}";
                            rowBuffer["BJ"] = mp.Value;
                            rowBuffer["XZBZ"] = Math.Round(pt.X, 3);
                            rowBuffer["YZBZ"] = Math.Round(pt.Y, 3);

                            // 坐标
                            Coordinate2D newCoordinate = new Coordinate2D(pt.X, pt.Y);
                            // 创建点几何
                            MapPointBuilderEx mapPointBuilderEx = new(new Coordinate2D(pt.X, pt.Y));
                            // 给新添加的行设置形状
                            rowBuffer[featureClassDefinition.GetShapeField()] = mapPointBuilderEx.ToGeometry();

                            // 在表中创建新行
                            using Feature feature = featureClass.CreateRow(rowBuffer);
                            context.Invalidate(feature);      // 标记行为无效状态
                        }
                    }
                }

            }, featureClass);

            MapCtlTool.OpenEdit();
            // 执行编辑操作
            editOperation.Execute();
            // 保存
            Project.Current.SaveEditsAsync();
        }

        // 创建线要素
        private void CreatePolyline(string fcPath, SpatialReference sr, Dictionary<List<List<MapPoint>>, string> mapPoints)
        {
            string gdbPath = fcPath.TargetWorkSpace();
            string fcName = fcPath.TargetFcName();

            // 创建一个ShapeDescription
            var shapeDescription = new ShapeDescription(GeometryType.Polyline, sr)
            {
                HasM = false,
                HasZ = false
            };

            // 定义字段
            #region

            var bj = new ArcGIS.Core.Data.DDL.FieldDescription("BJ", FieldType.String);
            bj.AliasName = "宗地号";
            bj.Length = 254;

            var jzxh = new ArcGIS.Core.Data.DDL.FieldDescription("JZXH", FieldType.String);
            jzxh.AliasName = "界址线号";
            jzxh.Length = 10;
            #endregion

            // 打开数据库gdb
            using Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(gdbPath)));
            // 收集字段列表
            var fieldDescriptions = new List<ArcGIS.Core.Data.DDL.FieldDescription>()
            {
                bj,jzxh,
            };

            // 创建FeatureClassDescription
            var fcDescription = new FeatureClassDescription(fcName, fieldDescriptions, shapeDescription);
            // 创建SchemaBuilder
            SchemaBuilder schemaBuilder = new SchemaBuilder(gdb);
            // 将创建任务添加到DDL任务列表中
            schemaBuilder.Create(fcDescription);
            // 执行DDL
            bool success = schemaBuilder.Build();

            // 创建要素并添加到要素类中
            using FeatureClass featureClass = gdb.OpenDataset<FeatureClass>(fcName);
            /// 构建线要素
            // 创建编辑操作对象
            EditOperation editOperation = new EditOperation();
            editOperation.Callback(context =>
            {
                // 获取要素定义
                FeatureClassDefinition featureClassDefinition = featureClass.GetDefinition();
                // 循环创建点
                foreach (var mp in mapPoints)
                {
                    var mpList = mp.Key;
                    for (int j = 0; j < mpList.Count; j++)
                    {
                        for (int k = 0; k < mpList[j].Count - 1; k++)
                        {
                            // 创建RowBuffer
                            using RowBuffer rowBuffer = featureClass.CreateRowBuffer();
                            // 创建点集合
                            MapPoint initPt = mpList[j][k];
                            MapPoint nextPt = mpList[j][k + 1];

                            List<MapPoint> points = new List<MapPoint>
                                    {
                                                initPt, nextPt
                                    };

                            // 写入字段值
                            // 写入字段值和标记代码
                            int xh = k == mpList[j].Count - 2 ? 1 : k + 1;
                            rowBuffer["JZXH"] = $"J{xh}";

                            rowBuffer["BJ"] = mp.Value;

                            // 创建线几何
                            Polyline polylineWithAttrs = PolylineBuilderEx.CreatePolyline(points);

                            // 给新添加的行设置形状
                            rowBuffer[featureClassDefinition.GetShapeField()] = polylineWithAttrs;

                            // 在表中创建新行
                            using Feature feature = featureClass.CreateRow(rowBuffer);
                            context.Invalidate(feature);      // 标记行为无效状态
                        }
                    }
                }

            }, featureClass);

            MapCtlTool.OpenEdit();
            // 执行编辑操作
            editOperation.Execute();
            // 保存
            Project.Current.SaveEditsAsync();
        }


        private void btn_help_Click(object sender, RoutedEventArgs e)
        {
            string url = "https://blog.csdn.net/xcc34452366/article/details/148708195";
            UITool.Link2Web(url);
        }


        private List<string> CheckData(string fc, string nameField, string qlrField)
        {
            List<string> result = new List<string>();

            string fieldResult = CheckTool.CheckFieldValueSpace(fc, new List<string>{ nameField, qlrField});
            if (fieldResult != "")
            {
                result.Add(fieldResult);
            }


            return result;
        }


        private void combox_field_DropDown(object sender, EventArgs e)
        {
            UITool.AddTextFieldsToComboxPlus(combox_fc.ComboxText(), combox_field);
        }

        private void openGDBPathButton_Click(object sender, RoutedEventArgs e)
        {
            textGDBPath.Text = UITool.OpenDialogFolder();
        }

        private void combox_qlrField_DropDown(object sender, EventArgs e)
        {
            UITool.AddTextFieldsToComboxPlus(combox_fc.ComboxText(), combox_qlrField);
        }
    }
}
